
package com.idealighter.game.games.xzdd.manager;

import com.google.common.collect.Multimap;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.dictionary.dic.XzddRoomDic;
import com.idealighter.game.dictionary.dic.XzddRoomTypeDic;
import com.idealighter.game.dictionary.domain.XzddRoomDomain;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.games.common.AbstractRoom;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.RoomState;
import com.idealighter.game.games.xzdd.dto.ExchangeInfo;
import com.idealighter.game.games.xzdd.dto.HuPaiItemInfo;
import com.idealighter.game.games.xzdd.dto.RoomInfo;
import com.idealighter.game.games.xzdd.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.xzdd.dto.TingPaiItemInfo;
import com.idealighter.game.games.xzdd.message.ResDrawMsg;
import com.idealighter.game.games.xzdd.message.ResDrewMsg;
import com.idealighter.game.games.xzdd.message.ResEnterGameHallMsg;
import com.idealighter.game.games.xzdd.message.ResEnterRoomMsg;
import com.idealighter.game.games.xzdd.message.ResEnterTableMsg;
import com.idealighter.game.games.xzdd.message.ResExchangeMsg;
import com.idealighter.game.games.xzdd.message.ResExchangeOverMsg;
import com.idealighter.game.games.xzdd.message.ResExchangeTableMsg;
import com.idealighter.game.games.xzdd.message.ResExitRoomMsg;
import com.idealighter.game.games.xzdd.message.ResExitTableMsg;
import com.idealighter.game.games.xzdd.message.ResFastEnterTableMsg;
import com.idealighter.game.games.xzdd.message.ResGameOverMsg;
import com.idealighter.game.games.xzdd.message.ResGrabAbleMsg;
import com.idealighter.game.games.xzdd.message.ResGrabedMsg;
import com.idealighter.game.games.xzdd.message.ResHuMsg;
import com.idealighter.game.games.xzdd.message.ResHuPaiMsg;
import com.idealighter.game.games.xzdd.message.ResMissingMsg;
import com.idealighter.game.games.xzdd.message.ResMissingOverMsg;
import com.idealighter.game.games.xzdd.message.ResOtherEnterTableMsg;
import com.idealighter.game.games.xzdd.message.ResPlayMsg;
import com.idealighter.game.games.xzdd.message.ResReadyMsg;
import com.idealighter.game.games.xzdd.message.ResReadyOverMsg;
import com.idealighter.game.games.xzdd.message.ResResetMsg;
import com.idealighter.game.games.xzdd.message.ResTingPaiMsg;
import com.idealighter.game.games.xzdd.struct.XzddGangType;
import com.idealighter.game.games.xzdd.struct.XzddGrabType;
import com.idealighter.game.games.xzdd.struct.XzddHuType;
import com.idealighter.game.games.xzdd.struct.XzddPlayerBill;
import com.idealighter.game.games.xzdd.struct.XzddRoom;
import com.idealighter.game.games.xzdd.struct.XzddSeat;
import com.idealighter.game.games.xzdd.struct.XzddTable;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMgr;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;

/**
 * 血战到底消息管理 .
 * 
 * @date 2016年9月2日 上午10:33:15
 *
 */
@Singleton
public class XzddMsgMgr {

  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private PlayerMgr playerMgr;
  @Inject
  private XzddDataMgr dataMgr;
  @Inject
  private XzddRoomDic roomDic;
  @Inject
  private XzddRoomTypeDic roomTypeDic;

  /**
   * 发送进入游戏大厅消息 .
   * 
   * @param player 玩家.
   */
  public void sendEnterGameHallMsg(Player player) {
    ResEnterGameHallMsg msg = new ResEnterGameHallMsg();

    Collection<XzddRoom> rooms = dataMgr.rooms();
    for (XzddRoom room : rooms) {
      XzddRoomDomain roomDom = roomDic.get(room.getId().intValue());
      if (roomDom.getIsActive() != 1) {
        continue;
      }
      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();

      roomTypeDetailInfo.setType(roomDom.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDom.getType()).getName());

      RoomInfo roomInfo = new RoomInfo();
      roomInfo.setRoomId(room.getId().intValue());
      roomInfo.setName(roomDom.getName());
      roomInfo.setType(roomDom.getType());
      roomInfo.setMaxNum(roomDom.getMaxNum());
      roomInfo.setFree(roomDom.getFree());
      roomInfo.setGeneral(roomDom.getGeneral());
      roomInfo.setCrowded(roomDom.getCrowded());
      roomInfo.setLower(roomDom.getLower());
      roomInfo.setUpper(roomDom.getUpper());
      roomInfo.setProportionGold(roomDom.getProportionGold());
      roomInfo.setProportionChips(roomDom.getProportionChips());
      roomInfo.setTabble(roomDom.getTable());
      roomInfo.setMaxOne(roomDom.getMaxOne());
      roomInfo.setMinOne(roomDom.getMinOne());
      roomInfo.setAfee(roomDom.getAfee());
      roomInfo.setInType(roomDom.getInType());
      roomInfo.setPlayerNum(room.getPlayers().size());
      roomInfo.setStatus(roomStatus(room).desc);
      roomInfo.setDisplayNames(roomDom.getDisplays());
      roomInfo.setPlaceHolder(roomDom.getPlaceHolder());
      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }

    msgWriter.writeMsg(player, msg);
  }

  /**
   * 房间状态，空闲,普通,拥挤,爆满 .
   * 
   * @param room .
   * @return
   */
  private RoomState roomStatus(XzddRoom room) {
    int playersNum = room.getPlayers().size();
    XzddRoomDomain roomDom = roomDic.get(room.getId().intValue());

    if (playersNum < roomDom.getMaxNum() * roomDom.getFree() / 100) {
      return RoomState.IDLE;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getGeneral() / 100) {
      return RoomState.GENERAL;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getCrowded() / 100) {
      return RoomState.CROWD;
    } else {
      return RoomState.FULL;
    }
  }

  /**
   * 发送进入桌子消息 .
   * 
   * @param player 玩家.
   */
  public void sendEnterRoomMsg(Player player) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    for (AbstractTable table : player.curRoom.tables()) {
      msg.getTables().add(table.tableInfo());
    }
    msg.setMembers(player.curRoom.memInfos());
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送进入桌子消息 .
   * 
   * @param player 玩家.
   * @param table .
   */
  public void sendEnterTableMsg(Player player, AbstractTable table) {
    ResEnterTableMsg msg = new ResEnterTableMsg();
    AbstractRoom room = table.room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : table.players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送快速进入结果消息 .
   * 
   * @param player 玩家.
   * @param res 0:成功,1:没有空位置
   */
  public void sendFastEnterTableMsg(Player player, int res) {
    ResFastEnterTableMsg msg = new ResFastEnterTableMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送其他人进入桌子消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendOtherEnterTableMsg(XzddSeat seat) {
    ResOtherEnterTableMsg msg = new ResOtherEnterTableMsg();
    msg.setMem(seat.table.room.memInfo(seat.getPlayerId()));
    for (Long playerId : seat.table.players()) {
      if (playerId != seat.getPlayerId()) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 发送退出桌子消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendExitTableMsg(XzddSeat seat) {
    ResExitTableMsg msg = new ResExitTableMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 发送退出房间消息 .
   * 
   * @param player 玩家.
   * @param res 0:退出成功,1:在牌桌中退出失败
   */
  public void sendExitRoomMsg(Player player, int res) {
    ResExitRoomMsg msg = new ResExitRoomMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送交换牌桌位置消息 .
   * 
   * @param player 玩家.
   * @param res 0:成功,1:已经准备不能交换桌子,2:当前房间没有空位置
   */
  public void sendExchangeTableMsg(Player player, int res) {
    ResExchangeTableMsg msg = new ResExchangeTableMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 向同桌的玩家发送该座位的玩家已经准备好 .
   * 
   * @param seat 座位信息.
   * @param res 0:成功,1:重复准备
   */
  public void sendReadyMsg(XzddSeat seat, int res) {
    ResReadyMsg msg = new ResReadyMsg();
    msg.setOrder(seat.getOrder());
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 发送定缺消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendMissingMsg(XzddSeat seat) {
    ResMissingMsg msg = new ResMissingMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 发送换牌消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendExchangeMsg(XzddSeat seat) {
    ResExchangeMsg msg = new ResExchangeMsg();
    msg.setPlayerId(seat.getPlayerId());
    msg.setOrder(seat.getOrder());
    sendTablePlayersMsg(seat.table, msg);
  }


  /**
   * 发送全部准备消息 .
   * 
   * @param table .
   */
  public void sendReadyOverMsg(XzddTable table) {
    List<XzddSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      XzddSeat seat = seats.get(i);
      ResReadyOverMsg msg = new ResReadyOverMsg();
      msg.setDealerOrder(table.dealer.getOrder());
      msg.setDealerPlayerId(table.dealer.getPlayerId());
      msg.setDice1(table.dice1);
      msg.setDice2(table.dice2);
      msg.setMjs(seat.cards.mjList());
      long playerId = seat.getPlayerId();
      msgWriter.writeMsg(playerId, msg);
    }
  }

  /**
   * 定缺结束消息 .
   * 
   * @param table .
   */
  public void sendMissingOverMsg(XzddTable table) {
    ResMissingOverMsg msg = new ResMissingOverMsg();
    List<XzddSeat> seats = table.seats;
    for (int i = 0; i < seats.size(); i++) {
      XzddSeat seat = seats.get(i);
      msg.getMissings().add(seat.getPlayerId() > 0 ? seat.cards.missing.val : 0);
    }
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 发送换牌结束消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendExchangeOverMsg(XzddSeat seat) {
    XzddTable table = seat.table;
    List<XzddSeat> seats = table.seats;
    ResExchangeOverMsg msg = new ResExchangeOverMsg();

    for (int i = 0; i < seats.size(); i++) {
      XzddSeat s = seats.get(i);
      ExchangeInfo exchangeInfo = new ExchangeInfo();
      exchangeInfo.setOrder(s.getOrder());
      exchangeInfo.setNum(s.exchangeNum);
      if (seat == s) {
        exchangeInfo.setMjs(s.exchangeMjs);
      }
      msg.getExchanges().add(exchangeInfo);
    }

    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送麻将出牌消息 .
   * 
   * @param seat 座位信息.
   * @param mj .
   */
  public void sendPlayMsg(XzddSeat seat, int mj) {
    ResPlayMsg msg = new ResPlayMsg();
    msg.setMj(mj);
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 发送抢牌消息 .
   * 
   * @param seat 座位信息.
   * @param pengAble .
   * @param gangAble .
   * @param huAble .
   */
  public void sendGrabAbleMsg(XzddSeat seat, boolean pengAble, boolean gangAble, boolean huAble) {
    ResGrabAbleMsg msg = new ResGrabAbleMsg();
    msg.setPeng(pengAble ? 1 : 0);
    msg.setGang(gangAble ? 1 : 0);
    msg.setHu(huAble ? 1 : 0);
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 向摸牌玩家发送摸牌消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendDrawMsg(XzddSeat seat, int mj) {
    ResDrawMsg msg = new ResDrawMsg();
    msg.setMj(mj);
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送玩家摸过牌,除了摸牌玩家 .
   * 
   * @param seat 座位信息.
   */
  public void sendDrewMsg(XzddSeat seat) {
    ResDrewMsg msg = new ResDrewMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());

    List<XzddSeat> seats = seat.table.seats;
    for (int i = 0; i < seats.size(); i++) {
      XzddSeat s = seats.get(i);
      if (s.getPlayerId() > 0 && s != seat) {
        msgWriter.writeMsg(s.getPlayerId(), msg);
      }
    }
  }

  /**
   * 发送血战到底胡牌提示消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendHuPaiMsg(XzddSeat seat) {
    ResHuPaiMsg msg = new ResHuPaiMsg();
    msg.setHuMjs(new ArrayList<>(seat.cards.getHuMjs().keySet()));
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送抢牌结果消息 .
   * 
   * @param seat 座位信息.
   * @param mj .
   */
  public void sendGrabedMsg(XzddSeat seat, XzddGrabType type, XzddGangType gangType, int mj) {

    ResGrabedMsg msg = new ResGrabedMsg();
    msg.setMj(mj);

    if (gangType == XzddGangType.AN_GANG) {
      msg.setType(5);
    } else if (gangType == XzddGangType.MIAN_XIA_GANG) {
      msg.setType(4);
    } else if (gangType == XzddGangType.ZHI_GANG) {
      msg.setType(2);
    } else {
      msg.setType(type.val);
    }

    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    XzddSeat nextPlaySeat = seat.table.nextPlaySeat;
    msg.setNextOrder(nextPlaySeat.getOrder());
    msg.setNextPlayerId(nextPlaySeat.getPlayerId());
    sendTablePlayersMsg(seat.table, msg);
  }

  /**
   * 发送听牌消息 .
   * 
   * @param seat 座位信息.
   * @param calcTingMjs . 听牌
   */
  public void sendTingPaiMsg(XzddSeat seat, Multimap<Integer, Integer> calcTingMjs) {
    ResTingPaiMsg msg = new ResTingPaiMsg();
    for (Entry<Integer, Collection<Integer>> tingPaiRtr : calcTingMjs.asMap().entrySet()) {
      TingPaiItemInfo tingPaiInfo = new TingPaiItemInfo();
      tingPaiInfo.setPlayMj(tingPaiRtr.getKey());
      tingPaiInfo.getHuMjs().addAll(tingPaiRtr.getValue());
      msg.getItems().add(tingPaiInfo);
    }

    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送胡牌信息 .
   * 
   * @param seat 座位信息.
   * @param isZiMo .
   * @param mj .
   * @param items .
   * @param huMultiple .
   * @param totalGolds .
   */
  public void sendHuMsg(XzddSeat seat, boolean isZiMo, XzddHuType huType, int mj,
      List<HuPaiItemInfo> items, int huMultiple, int totalGolds) {
    XzddTable table = seat.table;
    ResHuMsg msg = new ResHuMsg();
    msg.setOrder(seat.getOrder());
    msg.setMj(mj);
    msg.setType(isZiMo ? 0 : 1);
    msg.setIsQgh(huType == XzddHuType.QIANG_GANG_HU ? 1 : 0);
    msg.setHuPlayerName(seat.getPlayerName());

    if (huType == XzddHuType.QIANG_GANG_HU) {
      msg.setHuedPlayerName(playerMgr.selectPlayer(table.preMianXiaGangPlayer).getPlayerName());
    } else if (!isZiMo) {
      msg.setHuedPlayerName(playerMgr.selectPlayer(table.prePlayer).getPlayerName());
    }

    msg.setItems(items);
    msg.setTotalGolds(totalGolds);
    msg.setTotalMultiple(huMultiple);
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 向牌中的玩家发送游戏结束消息 .
   * 
   * @param table .
   */
  public void sendGameOver(XzddTable table) {
    ResGameOverMsg msg = new ResGameOverMsg();
    for (XzddPlayerBill playerBill : table.playerBills.values()) {
      msg.getItems().add(playerBill.toPlayerBillInfo());
    }
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 向同桌的玩家(包括自己)发送消息 .
   * 
   * @param table .
   * @param msg .
   */
  public void sendTablePlayersMsg(XzddTable table, ResMessage msg) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 发送游戏重置消息 .
   * 
   * @param table .
   */
  public void sendResetMsg(XzddTable table) {
    sendTablePlayersMsg(table, new ResResetMsg());
  }

  /**
   * 向同房间的玩家(包括自己)发送消息 .
   * 
   * @param room .
   * @param msg .
   */
  public void sendRoomPlayersMsg(XzddRoom room, ResMessage msg) {
    room.getPlayers().forEach(p -> msgWriter.writeMsg(p, msg));
  }
}
